using System.Collections.Generic;
using System.Net;
using System.Reflection;
using ENode.Configurations;
using ENode.EQueue;
using ENode.Eventing;
using ENode.Messaging;
using EQueue.Configurations;
using EQueue.Clients.Consumers;
using EQueue.Clients.Producers;
using ENodeMicro.Common;
using EQueue.Protocols;
using ENode.Commanding;

namespace ENodeMicro.CommandHost
{
    public static class ENodeExtensions
    {
        private static CommandService _commandService;
        private static CommandConsumer _commandConsumer;
        private static DomainEventPublisher _domainEventPublisher;
        private static DomainEventConsumer _eventConsumer;
        private static ApplicationMessagePublisher _applicationMessagePublisher;

        public static ENodeConfiguration BuildContainer(this ENodeConfiguration eNodeConfiguration)
        {
            eNodeConfiguration
                .GetCommonConfiguration()
                .BuildContainer();
            return eNodeConfiguration;
        }
        public static ENodeConfiguration UseEQueue(this ENodeConfiguration eNodeConfiguration)
        {
            var assemblies = new[] { Assembly.GetExecutingAssembly() };
            eNodeConfiguration.RegisterTopicProviders(assemblies);

            var configuration = eNodeConfiguration.GetCommonConfiguration();
            configuration.RegisterEQueueComponents();

            _commandService = new CommandService();
            configuration.SetDefault<ICommandService, CommandService>(_commandService);

            _domainEventPublisher = new DomainEventPublisher();
            configuration.SetDefault<IMessagePublisher<DomainEventStreamMessage>, DomainEventPublisher>(_domainEventPublisher);

            _applicationMessagePublisher = new ApplicationMessagePublisher();
            configuration.SetDefault<IMessagePublisher<IApplicationMessage>, ApplicationMessagePublisher>(_applicationMessagePublisher);

            return eNodeConfiguration;
        }
        public static ENodeConfiguration StartEQueue(this ENodeConfiguration eNodeConfiguration)
        {
            var nameServerEndpoint = new IPEndPoint(IPAddress.Loopback, ConfigSettings.NameServerPort);
            var nameServerEndpoints = new List<IPEndPoint> { nameServerEndpoint };

            #region Producers
            
            _commandService.InitializeEQueue(null, new ProducerSetting
            {
                NameServerList = nameServerEndpoints
            });
            _domainEventPublisher.InitializeEQueue(new ProducerSetting
            {
                NameServerList = nameServerEndpoints
            });
            _applicationMessagePublisher.InitializeEQueue(new ProducerSetting
            {
                NameServerList = nameServerEndpoints
            });

            #endregion

            #region Consumers
            
            _commandConsumer = new CommandConsumer()
                .InitializeEQueue("MemberCommandConsumerHostGroup",setting: new ConsumerSetting
                {
                    NameServerList = nameServerEndpoints,
                    ConsumeFromWhere = ConsumeFromWhere.FirstOffset
                });
            _commandConsumer
                .Subscribe("MemberCommandTopic");

            _eventConsumer = new DomainEventConsumer()
                .InitializeEQueue("MemberEventConsumerHostGroup", setting: new ConsumerSetting
                {
                    NameServerList = nameServerEndpoints,
                    ConsumeFromWhere = ConsumeFromWhere.FirstOffset
                });
            _eventConsumer
                .Subscribe("MemberEventTopic");
            #endregion


            _commandService.Start();
            _eventConsumer.Start();
            _commandConsumer.Start();

            _domainEventPublisher.Start();
            _applicationMessagePublisher.Start();

            return eNodeConfiguration;
        }
        public static ENodeConfiguration ShutdownEQueue(this ENodeConfiguration eNodeConfiguration)
        {
            _eventConsumer.Shutdown();
            _commandConsumer.Shutdown();
            _domainEventPublisher.Shutdown();
            _applicationMessagePublisher.Shutdown();
            _commandService.Shutdown();
            return eNodeConfiguration;
        }
    }
}